<?php
/***************************************************************************
    Copyright 2008 Bastiaan Grutters
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published 
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
***************************************************************************/

/*
 * This class contains all the functions needed to use and manage a shoutbox 
 */
class shoutbox {
	var $filters = Array();
	var $actions = Array();
	
	function get_chat( $user_id, $channel_id, $amount, $page, $initial = false ) {
		if( !$initial ) {
			$query = "SELECT timestamp " .
				"FROM chat_activity " .
				"WHERE user_id = " . $user_id . " AND channel_id = " . $channel_id;
			$result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			$row = mysql_fetch_array( $result, MYSQL_ASSOC );
		   if( isset( $row[ 'timestamp' ] ) ) {
			   $timestamp = $row[ 'timestamp' ];
		   }
		}
		else {
			$timestamp = 1;
		}
	    
	   if( $timestamp > 1 ) {
			$query = "SELECT count(*) " .
					"FROM chat " .
	    			"WHERE channel_id = $channel_id AND timestamp > $timestamp";
			$result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			$row = mysql_fetch_array( $result, MYSQL_ASSOC );
			if( $row[ 'count(*)' ] > $amount ) {
				$amount = $row[ 'count(*)' ];
			}
	   }
		$query = "SELECT * " .
	    		"FROM chat " .
	    		"WHERE channel_id = $channel_id " .
	    		"ORDER BY timestamp DESC " .
	    		"LIMIT " . ( ( $page - 1 ) * $amount ) . ", $amount";
	   $result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
	   $num = mysql_numrows( $result );
	   $items = Array();
	   while ( $row = mysql_fetch_object( $result ) ) {
			$items[] = $row;
	   }
	    
		return array_reverse( $items );
	}
	
	/*
	 * This function prints the supplied messages in a standard format, 
	 * optionally you can supply an array of key/value pairs which will be replaced in the message
	 */
	function print_messages( $messages, $timestamp, $highlight = Array() ) {
		if( count( $messages ) > 0 ) {
			$this->do_actions( 'before_messages', $messages );
						
			print( "<div id='chat-message-container'>" );
			foreach( $messages AS $message ) {
				$class = "";
				if( $message->timestamp > $timestamp ) {
					$class = " unseen-message";
				}
				
				if( is_array( $highlight ) ) {
					foreach( $highlight AS $key => $replace ) {
						$message->message = str_replace( $key, $replace, $message->message  );
					}
				}
?>
			<div class="chat-message<?php print( $class ); ?>">
				<small>
					<?php print( $this->apply_filters( 'print_user', $message->user_id ) ); ?>
					<?php print( $this->apply_filters( 'print_time', $message->timestamp ) ); ?>
				</small>
<?php
		if( $this->apply_filters( 'allow_administration', false ) ) {
			if( $message->blocked == 0 ) {
				print( " (<a href=\"block_message.php?chat_id=$message->chat_id\">Block</a>)" );
			}
			else {
				print( " (<a href=\"block_message.php?chat_id=$message->chat_id\">Unblock</a>)" );
			}
		}
		
		print( "<br />\r\n" );
		
		if( $message->blocked == 1 ) {
			if( $this->apply_filters( 'allow_administration', false ) ) {
				print( "<pre>[This message has been marked as inappropriate]:\r\n\r\n" . stripslashes( $message->message ) . "</pre><br />" );
			}
			else {
				print( "<pre>[This message has been marked as inappropriate]</pre>" );
			}
		}
		else {
?>
				<pre><?php print( stripslashes( $message->message ) ); ?></pre>
<?php
		}
?>
			</div>
			<br />
<?php
			}
?>
				</div>
				<div id="last-timestamp" class="hidden"><?php print( $messages[count( $messages ) - 1]->timestamp ); ?></div>
<?php
			$this->do_actions( 'after_messages', $messages );
		}
		else {
			print( "There are no messages." );
		}
	}
	
	function print_channel_overview( $user_id, $channel_id, $user_groups = Array() ) {
	   $groups = "group_id = -1";
	   if( is_array( $user_groups ) && count( $user_groups ) > 0 ) {
	   	$groups = "group_id IN ( " . implode( ',', $user_groups ) . " ) OR " . $groups;
	   }
	   
	   $query = "SELECT * " .
	    		"FROM chat_channels " .
	    		"WHERE $groups " .
	    		"ORDER BY group_id ASC, NAME ASC";
	   $result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
		$num = mysql_numrows( $result );
		print( $this->apply_filters( 'print_public_title', 'Public' ) . ': ' );
		$in_group = false;
		$first = true;
	   while ( $row = mysql_fetch_object( $result ) ) {
	    	if( !$in_group && $row->group_id != -1 ) {
	    		print( "<br />" . $this->apply_filters( 'print_group_title', 'Group' ) . ": " );
	    		$in_group = true;
	    		$first = true;
	    	}
	    	if( !$first ) {
	    		print( ', ' );
	    	}
	    	
			$query2 = "SELECT count(*) " .
					"FROM chat " .
					"LEFT JOIN chat_activity ON chat.channel_id = chat_activity.channel_id " .
					"WHERE chat_activity.user_id = $user_id AND " .
							"chat.channel_id = $row->channel_id " .
						" AND IFNULL( chat_activity.timestamp < chat.timestamp, FALSE ) ";
			$result2 = mysql_query( $query2 ) or die( "Query failed : " . mysql_error() );
			$row2 = mysql_fetch_array( $result2, MYSQL_ASSOC );
			$count = $row2[ 'count(*)' ];
			$strong = false;
			if( $count == 0 ) {
				$count = '';
				$query2 = "SELECT count(*) " .
						"FROM chat_activity " .
						"WHERE user_id = $user_id AND " .
								"channel_id = $row->channel_id";
				$result2 = mysql_query( $query2 ) or die( "Query failed : " . mysql_error() );
				$row2 = mysql_fetch_array( $result2, MYSQL_ASSOC );
				if( $row2[ 'count(*)' ] == 0 ) {
					$strong = true;
				}
			}
			else {
				$count = ' (' . number_format( $count ) . ')';
			}
	    	if( $row->channel_id == $channel_id ) {
	    		print( '<strong class="current-channel">' . $row->name . $count . '</strong>' );
	    	}
	    	else {
	    		if( $strong ) {
	    			$title = "<strong>" . $row->name . $count . "</strong>";
	    		}
	    		else {
	    			$title = $row->name . $count;
	    		}
	    		print( "<a href=\"javascript:void(null);\" onclick=\"YAHOO.shoutbox.updateChat( true, $row->channel_id );\">$title</a>" );
	    	}
	    	$first = false;
	   }
	   print( "<br />" );
	}
	
	function get_unread_chat_message_count( $user_id, $group_id = -1 ) {
		$query = "SELECT count(*) " .
				"FROM chat " .
				"LEFT JOIN chat_activity ON chat.channel_id = chat_activity.channel_id " .
				"WHERE chat_activity.user_id = $user_id AND " .
						"chat.channel_id IN ( SELECT chat_channels.channel_id " .
							"FROM chat_channels " .
			// Perhaps also check f" . $_SESSION[ 'ruler_id' ] . "or chat messages in public channels...or perhaps optional
							"WHERE group_id = $group_id )" .
					" AND IFNULL( chat_activity.timestamp < chat.timestamp, FALSE ) ";
		//print( "Query: $query <br />" );
		$result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
		$row = mysql_fetch_array( $result, MYSQL_ASSOC );
		return $row[ 'count(*)' ];
	}
	
	/*
	 * Note: This form should not be available to anyone, only to administrative users or equivilant
	 */
	function print_chat_channel_form( $action, $group_id, $channel_id = -1 ) {
		if( $channel_id == -1 || !is_numeric( $channel_id ) ) {
			if( !isset( $group_id ) ) {
				$free_group = true;
				$group_id = '-1';
			}
			else {
				$free_group = false;
			}
			$name = '';
		}
		else {
			$query = "SELECT * " .
					"FROM chat_channels " .
					"WHERE channel_id = $channel_id";
			$result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			$row = mysql_fetch_array( $result, MYSQL_ASSOC );
			if( !isset( $row[ 'channel_id' ] ) ) {
				if( !isset( $group_id ) ) {
					$free_group = true;
					$group_id = '-1';
				}
				else {
					$free_group = false;
				}
				$name = '';
			}
			else {
				$real_channel_id = $row[ 'channel_id' ];
				$group_id = stripslashes( $row[ 'group_id' ] );
				$name = stripslashes( $row[ 'name' ] );
			}
		}
	?>
			<form method="post" action="<?php print( $action ); ?>">
	<?php
		if( isset( $real_channel_id ) ) {
	?>
				<input type="hidden" name="channel_id" value="<?php print( $real_channel_id ); ?>" />
	<?php
		}
	?>
				Channel name:<br />
				<input type="textfield" size="20" name="name" value="<?php print( $name ); ?>" /><br />
	<?php
		if( $free_group ) {
	?>
				Group id: <br />
				<input type="textfield" size="4" name="group_id" value="<?php print( $group_id ); ?>" /><br />
	<?php		
		}
		else {
	?>
				<input type="hidden" name="group_id" value="<?php print( $group_id ); ?>" />
	<?php		
		} 
	?>
				<br />
				<input type="submit" value="Confirm" /> 
			</form>
	<?php
	}
	
	/*
	 * Note: This form should not be available to anyone, only to administrative users or equivilant
	 */
	function process_create_chat_channel_form() {
		if( isset( $_POST[ 'channel_id' ] ) && is_numeric( $_POST[ 'channel_id' ] ) ) {
			$channel_id = $_POST[ 'channel_id' ];
			$edit = true;
		}
		else {
			$edit = false;
		}
		
		if( isset( $_POST[ 'name' ] ) && $_POST[ 'name' ] != '' ) {
			$name = mysql_real_escape_string( $_POST[ 'name' ] );
		}
		else {
			return "Fill in a channel name.";
		}
		
		if( isset( $_POST[ 'group_id' ] ) && is_numeric( $_POST[ 'group_id' ] ) ) {
			$group_id = $_POST[ 'group_id' ];
		}
		else {
			return "Fill a numeric group id.";
		}
				
		if( $edit ) {
			$query = "UPDATE chat_channels " .
					"SET name = '$name', group_id = '$group_id' " .
					"WHERE channel_id = $channel_id";
			mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			return 'Chat channel settings updated';
		}
		else {
			$query = "INSERT INTO chat_channels " .
					"( name, group_id ) " .
					"VALUES( '$name', $group_id )";
			mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			return 'Chat channel succesfully added';
		}
	}
	
	function remove_chat_channel( $channel_id ) {
		$query = "DELETE FROM chat_channels " .
				"WHERE channel_id = $channel_id";
		mysql_query( $query ) or die( "Query failed : " . mysql_error() );
		return 'Chat channel removed';
	}
	
	/*
	 * Perform the supplied function with the specified data
	 * The function displayed should return a value or nothing 
	 * if nothing should be printed/used
	 */
	function add_filter( $filter_name, $function ) {
		if( isset( $this->filters[$filter_name] ) ) {
			$this->filters[$filter_name][] = $function;
			return true;
		}
		else {
			 // Check if this filter name is correct
			if( $filter_name == 'print_user' || $filter_name == 'print_time' || 
				 $filter_name == 'allow_administration' ||
				 $filter_name == 'print_public_title' || $filter_name == 'print_group_title' ) {
				$this->filters[$filter_name] = Array();
				$this->filters[$filter_name][] = $function;
				return true;
			}
			else {
				return false;
			}
		}
	}
	
	/*
	 * Perform the supplied function at the supplied action
	 */
	function add_action( $action_name, $function ) {
		if( isset( $this->actions[$action_name] ) ) {
			$this->actions[$action_name][] = $function;
			return true;
		}
		else {
			 // Check if this action name is correct
			if( $action_name == 'before_messages' || $action_name == 'after_messages' ) {
				$this->actions[$action_name] = Array();
				$this->actions[$action_name][] = $function;
				return true;
			}
			else {
				return false;
			}
		}
	}
	
	function do_actions( $action_name, $value = null ) {
		if( isset( $this->actions[$action_name] ) && is_array( $this->actions[$action_name] ) ) {
			foreach( $this->actions[$action_name] as $action ) {
				if( isset( $value ) ) {
					call_user_func( $action, $value );
				}
				else {
					call_user_func( $action );
				}
			}
		}
	}
	
	function apply_filters( $filter_name, $value ) {
		if( isset( $this->filters[$filter_name] ) && is_array( $this->filters[$filter_name] ) ) {
			foreach( $this->filters[$filter_name] as $action ) {
				$value = call_user_func( $action, $value );
			}
		}
		return $value;
	}
	
	function add_message( $text, $user_id, $channel_id, $user_groups = Array() ) {
		if( $text != '' && strlen( $text ) > 1 ) {
			$query = "SELECT group_id " .
					"FROM chat_channels " .
					"WHERE channel_id = $channel_id";
			$result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			$row = mysql_fetch_array( $result, MYSQL_ASSOC );
			if( isset( $row[ 'group_id' ] ) && ( $row[ 'group_id' ] == -1 || in_array( $row[ 'group_id' ], $user_groups ) ) ) {
				$time = time();
				$query = "SELECT count(*) FROM chat " .
						"WHERE user_id = $user_id AND message LIKE '$text' AND channel_id = $channel_id AND " .
								"timestamp > " . ( $time - 10 );
				$result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
				$row = mysql_fetch_array( $result, MYSQL_ASSOC );
				
				if( $row[ 'count(*)' ] == 0 ) {
					$query = "INSERT INTO chat " .
							"( message, user_id, channel_id, timestamp )" .
							"VALUES( '$text', $user_id, $channel_id, $time )";
					mysql_query( $query ) or die( "Query failed : " . mysql_error() );
				}
				else {
					return false;
				}
			}
			else {
				return false;
			}
		}
		else {
			return false;
		}
	}
	
	function print_shoutbox_content( $user_id, $channel_id, $user_groups = Array(), $how_many = 10, $page = 1, $force_print = false, $highlight = Array() ) {
		$messages = $this->get_chat( $user_id, $channel_id, $how_many, $page, $force_print );
		$previous_last_chat = -1;
		$query = "SELECT timestamp " .
				"FROM chat_activity " .
				"WHERE user_id = $user_id AND channel_id = $channel_id";
		$result = mysql_query( $query ) or die( "Query failed : " . mysql_error() );
		$row = mysql_fetch_array( $result, MYSQL_ASSOC );
		if( isset( $row[ 'timestamp' ] ) ) {
			$previous_last_chat = $row[ 'timestamp' ];
		}
		
		if( $force_print || ( count( $messages ) != 0 && $messages[count( $messages ) - 1]->timestamp > $previous_last_chat ) || count( $messages ) == 0 ) {
			$last_chat = time();
			
			if( isset( $row[ 'timestamp' ] ) ) {
				$query = "UPDATE chat_activity " .
						"SET timestamp = $last_chat " .
						"WHERE user_id = $user_id AND channel_id = $channel_id";
				mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			}
			else {
				$query = "INSERT INTO chat_activity " .
						" ( `user_id`, `channel_id`, `timestamp` ) " .
						"VALUES( $user_id, $channel_id, $last_chat )";
				mysql_query( $query ) or die( "Query failed : " . mysql_error() );
			}
			$this->print_channel_overview( $user_id, $channel_id, $user_groups );
			print( "<br />" );
			$this->print_messages( $messages, $previous_last_chat, $highlight );
?>
						<div class="hidden" id="channel-id"><?php print( $channel_id ); ?></div>
<?php
		}
		else {
			print( 'up-to-date' );
		}
		
	}
}

?>
